#include "StdAfx.h"
#include "ControlContext.h"
#include "TargetController.h"
#include "TargetControlLogic.h"
#include "Target.h"

#include "EntityControl.h"

#include "Launcher.h"

TargetController::TargetController(
	TargetControlLogic* targetControlLogic)
	:targetControlLogic(targetControlLogic)
{
	currentTargetIndex = 0;
	currentProjectileTargetIndex = 0;
}

TargetController::~TargetController(void)
{
	//delete targetControlLogic;
}

bool TargetController::apply(
	EntityControl* entityControl, const ControlContext& context)
{
	/*NxActor* actor = entityControl->getPhysicsActor()->getNxActor();
	Ogre::SceneNode* ogreNode = entityControl->getPhysicsActor()->getOgreNode();*/

	// If target exists
	if( !targetControlLogic->targets.empty() )
	{


		/*actor->setLinearVelocity(NxVec3(0,0,0));
		actor->setAngularVelocity(NxVec3(0,0,0));*/


		// Get the next target
		Target* target = targetControlLogic->
			targets.at(currentTargetIndex);

		// Distance from target
		Ogre::Vector3 distanceFromTarget =
			target->position - entityControl->getPosition();





		// Add distance from mark
		if(target->mark != NULL)
			distanceFromTarget += target->mark->getParentSceneNode()->getPosition();



		// If target reached, advance to thy next target
		if(distanceFromTarget.length() < target->proximityRadius)
		{
			currentTargetIndex++;
			if(currentTargetIndex >= targetControlLogic->targets.size())
				currentTargetIndex = 0;
		}

		// Direction to the mark
		Ogre::Vector3 targetDirection =
			distanceFromTarget.normalisedCopy();

		// Get the current facing direction
		Ogre::Vector3 ahead =
			entityControl->getOrientation() * Ogre::Vector3::UNIT_Z;

		// Get the turning axis
		Ogre::Vector3 turnAxis =
			ahead.crossProduct(targetDirection);


		//actor->raiseBodyFlag(NX_BF_DISABLE_GRAVITY);

		//Ogre::Vector3 force = ahead * ahead.dotProduct(targetDirection) * targetControlLogic->maxForce;
		Ogre::Vector3 torque = turnAxis * targetControlLogic->maxTorque;
		Ogre::Vector3 force = targetDirection * targetControlLogic->maxForce;
		entityControl->addForce(Ogre::Vector3(force.x, force.y, force.z)*0.1);
		//actor->addForce(NxVec3(targetDirection.x, targetDirection.y, targetDirection.z)*1000);
		entityControl->addTorque(Ogre::Vector3(torque.x, torque.y, torque.z)*0.001);

	}
	/*ogreNode->setOrientation(actor->getGlobalOrientationQuat().w,
	actor->getGlobalOrientationQuat().x,
	actor->getGlobalOrientationQuat().y,
	actor->getGlobalOrientationQuat().z);
	ogreNode->setPosition(actor->getGlobalPosition().x,
	actor->getGlobalPosition().y,
	actor->getGlobalPosition().z);*/

	// Shooting from launchers
	if( !targetControlLogic->launchers.empty() )
	{
		// Iterate for every attached launcher
		std::vector<Launcher*>::iterator iLauncher = targetControlLogic->launchers.begin();
		while(iLauncher != targetControlLogic->launchers.end())
		{
			Launcher* launcher = *iLauncher;

			// Update cooldown, if 0, then shoot
			if( launcher->setCooldownRemaining(launcher->getCooldownRemaining() - context.dt) <= 0 )
			{

				// Create new Projectile from current launcher
				TargetController::Projectile newProjectile(launcher->getProjectile());
				newProjectile.modelMeshName = launcher->getProjectile().modelMeshName;
				newProjectile.position = launcher->getProjectile().position;


				// Get the point of the entity looking at
				Ogre::Vector3 entityLookingAtPoint = Ogre::Vector3::ZERO;
				Target* target;


				if( !targetControlLogic->ProjectileTargets.empty()  || entityControl->isParameterFilled("target"))
				{
					if(entityControl->isParameterFilled("target"))
					{
						VectorEntityParameter * param =  (VectorEntityParameter*) entityControl->getParameter("target");
						target = new Target(param->getVectorValue(),20);
						entityLookingAtPoint = target->position;
					}
					else
					{
						// Get the next target
						target = targetControlLogic->
							ProjectileTargets.at(currentProjectileTargetIndex);


						currentProjectileTargetIndex++;
						if(currentProjectileTargetIndex >= targetControlLogic->ProjectileTargets.size())
							currentProjectileTargetIndex = 0;

						if(target->mark != NULL)
							entityLookingAtPoint = target->mark->getParentSceneNode()->getPosition();
						else
						{
							entityLookingAtPoint = target->position;
							entityLookingAtPoint.x += (rand()% (int)target->proximityRadius - target->proximityRadius/2);
							entityLookingAtPoint.y += (rand()% (int)target->proximityRadius - target->proximityRadius/2);
							entityLookingAtPoint.z += (rand()% (int)target->proximityRadius - target->proximityRadius/2);
						}

					}
					entityLookingAtPoint -= launcher->getProjectile().position;

					Ogre::Vector3 entityDirection = entityLookingAtPoint - entityControl->getPosition();

					entityDirection.normalise();

					// Get the direction
					Ogre::Vector3 launcherVelocity = launcher->getProjectile().velocity;
					newProjectile.velocity = Ogre::Vector3(
						entityDirection.x * launcherVelocity.x,
						entityDirection.y * launcherVelocity.y,
						entityDirection.z * launcherVelocity.z);

					// Add the new Projectile to the list
					projectiles.push_back(newProjectile);

					// Reset cooldown
					launcher->resetCooldown();
				}
			}

			iLauncher++;
		}
	}

	return true;

}

bool TargetController::isSpawningNeeded()
{
	return !projectiles.empty();
}

TargetController::Projectile TargetController::getNextSpawnItem()
{
	TargetController::Projectile projectile = projectiles.back();
	projectiles.pop_back();
	return projectile;
}
